package de.akabahn.ebd.fst;

import java.util.List;

import de.akabahn.ebd.fst.Tfz.Direction;

/**
 * Interface for the "Fahrsteuerung" application, implementations of this
 * interface are created using the <code>FahrSteuerungAdapterFactory</code>.
 * 
 * @author Peter Eimann
 * @since 0.2
 * @version 1.0
 * @see FahrSteuerungAdapterFactory
 */
public interface FahrSteuerungAdapter {

	/**
	 * Establish the connection to the remote telnet server
	 * 
	 * @throws FahrSteuerungException
	 */
	public abstract void start() throws FahrSteuerungException;

	/**
	 * Disconnect from the remote telnet server
	 * 
	 * @throws FahrSteuerungException
	 */
	public abstract void stop() throws FahrSteuerungException;

	/**
	 * Return if the current lifecycle status is <code>started</code> or not
	 * 
	 * @return <code>true</code> if the lifecylce status is <code>started</code>
	 */
	public abstract boolean isStarted();

	/**
	 * Register the "Triebfahrzeug" with the specified address at the
	 * "Fahrsteuerung"
	 * 
	 * @param address
	 *            The address of the "Triebfahrzeug"
	 * @return <code>true</code> if the registration was successful
	 * @throws IllegalArgumentException
	 *             thrown if the input parameters are invalid
	 * @throws FahrSteuerungException
	 */
	public abstract boolean init(String address) throws FahrSteuerungException;

	/**
	 * Return a list containing information about all the "Triebfahrzeuge" that
	 * are currently registered.
	 * 
	 * @return The list of registered "Triebfahrzeuge" (will be
	 *         <code>empty</code> and not <code>null</code> if none are
	 *         registered ), ordered by their address and mode
	 * @throws FahrSteuerungException
	 * @see #inf(String...)
	 * @see Tfz
	 */
	public abstract List<Tfz> inf() throws FahrSteuerungException;

	/**
	 * Return a list containing information about the "Triebfahrzeuge" with the
	 * given address.<br>
	 * The query for "Triebfahrzeuge" at a given track is not supported because
	 * the application then only returns the tfz addresses without any other
	 * information. If <code>tfzList</code> is empty, the list will contain all
	 * registered "Triebfahrzeuge".
	 * 
	 * @param tfzList
	 *            The address (only "Triebfahrzeuge" with this address are
	 *            returned), if all registered "Triebfahrzeuge" should be
	 *            returned, an <code>empty string</code> has to be used
	 * @return The list of registered "Triebfahrzeuge" with the specified
	 *         address (will be <code>empty</code> and not <code>null</code> if
	 *         none are registered), ordered by their address and mode
	 * @throws IllegalArgumentException
	 *             thrown if the input parameters are invalid
	 * @throws FahrSteuerungException
	 * @see #inf()
	 * @see Tfz
	 */
	public abstract List<Tfz> inf(String... tfzList) throws FahrSteuerungException;

	/**
	 * Deregister the "Triebfahrzeug" with the specified address at the
	 * "Fahrsteuerung".
	 * 
	 * @param address
	 *            The address of the Triebfahrzeug
	 * @return <code>true</code> if the deregistration was successful
	 * @throws IllegalArgumentException
	 *             thrown if the input parameters are invalid
	 * @throws FahrSteuerungException
	 */
	public abstract boolean term(String address) throws FahrSteuerungException;

	/**
	 * Stop the "Triebfahrzeug" with the specified address and switch it to
	 * manual operation mode.
	 * 
	 * @param address
	 *            The address of the Triebfahrzeug
	 * @return <code>true</code> if the stop was successful
	 * @throws IllegalArgumentException
	 *             thrown if the input parameters are invalid
	 * @throws FahrSteuerungException
	 */
	public abstract boolean stop(String address) throws FahrSteuerungException;

	/**
	 * Convenience method if the direction of the "Triebfahrzeug" should just be
	 * changed instead of setting it to a concrete value.
	 * 
	 * @param address
	 *            The address of the Triebfahrzeug
	 * @return <code>true</code> if the direction change was successful
	 * @throws FahrSteuerungException
	 * @see #rich(String, Tfz.Direction)
	 */
	public abstract boolean rich(String address) throws FahrSteuerungException;

	/**
	 * Set or change the direction of the "Triebfahrzeug" with the specified
	 * address. If the <code>direction</code> is not specified, the current
	 * direction of the "Triebfahrzeug" is changed, otherwise the direction is
	 * set to the specified value.
	 * 
	 * @param address
	 *            The address of the Triebfahrzeug
	 * @param direction
	 *            The new direction, <code>REVERSE</code> means reverse
	 *            direction, <code>ARROW</code> means arrow direction. If set to
	 *            <code>null</code>, the current direction is changed.
	 * @return <code>true</code> if the direction change was successful
	 * @throws IllegalArgumentException
	 *             thrown if the input parameters are invalid
	 * @throws FahrSteuerungException
	 * @see #rich(String)
	 */
	public abstract boolean rich(String address, Direction direction) throws FahrSteuerungException;

	/**
	 * Reverse the direction of the "Triebfahrzeug" with the specified address.
	 * 
	 * @param address
	 *            The address of the Triebfahrzeug
	 * @return <code>true</code> if the reverse was successful
	 * @throws IllegalArgumentException
	 *             thrown if the input parameters are invalid
	 * @throws FahrSteuerungException
	 */
	public abstract boolean umk(String address) throws FahrSteuerungException;

	/**
	 * Set the speed of the "Triebfahrzeug". Speed can be in the range between 0
	 * and 100, where 0 means stop and 100 maximum speed.
	 * 
	 * @param address
	 *            The address of the Triebfahrzeug
	 * @param speed
	 *            The speed of the Triebfahrzeug
	 * @return <code>true</code> if the speed change was successful
	 * @throws IllegalArgumentException
	 *             thrown if the input parameters are invalid
	 * @throws FahrSteuerungException
	 */
	public abstract boolean go(String address, int speed) throws FahrSteuerungException;

	/**
	 * Set the "Triebfahrzeug" in automatic operation. Track specifies the
	 * current location of the "Triebfahrzeug".
	 * 
	 * @param address
	 *            The address of the Triebfahrzeug
	 * @param track
	 *            The location of the Triebfahrzeug
	 * @return <code>true</code> if setting the automatic mode was successful
	 * @throws IllegalArgumentException
	 *             thrown if the input parameters are invalid
	 * @throws FahrSteuerungException
	 */
	public abstract boolean auto(String address, String track) throws FahrSteuerungException;

	/**
	 * Activate or deactivate one of five possible special functions of a
	 * "Triebfahrzeug".
	 * 
	 * @param address
	 *            The address of the Triebfahrzeug
	 * @param function
	 *            The function to activate or deactivate
	 * @param activate
	 * 			  <code>null</code> if the function should be toggled,
	 *            <code>true</code> if the function should be activated, 
	 *            <code>false</code> it it should be deactivated
	 * @return <code>true</code> if setting the function was successful
	 * @throws IllegalArgumentException
	 *             thrown if the input parameters are invalid
	 * @throws FahrSteuerungException
	 */
	public abstract boolean setf(String address, int function, Boolean activate) throws FahrSteuerungException;

	/**
	 * Activate five possible special functions of a "Triebfahrzeug" for a
	 * limited time.
	 * 
	 * @param address
	 *            The address of the Triebfahrzeug
	 * @param function
	 *            The function to activate
	 * @return <code>true</code> if setting the function was successful
	 * @throws IllegalArgumentException
	 *             thrown if the input parameters are invalid
	 * @throws FahrSteuerungException
	 */
	public abstract boolean seti(String address, int function) throws FahrSteuerungException;

	/**
	 * Hold the "Triebfahrzeug" with the specified address.
	 * 
	 * @param address
	 *            The address of the Triebfahrzeug
	 * @return <code>true</code> if the hold was successful
	 * @throws IllegalArgumentException
	 *             thrown if the input parameters are invalid
	 * @throws FahrSteuerungException
	 */
	public abstract boolean hold(String address) throws FahrSteuerungException;

	/**
	 * End the hold mode for "Triebfahrzeug" with the specified address.
	 * 
	 * @param address
	 *            The address of the Triebfahrzeug
	 * @return <code>true</code> if the cont was successful
	 * @throws IllegalArgumentException
	 *             thrown if the input parameters are invalid
	 * @throws FahrSteuerungException
	 */
	public abstract boolean cont(String address) throws FahrSteuerungException;

	/**
	 * Expect the next signal to be clear for the "Triebfahrzeug" with the
	 * specified address.
	 * 
	 * @param address
	 *            The address of the Triebfahrzeug
	 * @return <code>true</code> if the bef2 was successful
	 * @throws IllegalArgumentException
	 *             thrown if the input parameters are invalid
	 * @throws FahrSteuerungException
	 */
	public abstract boolean bef2(String address) throws FahrSteuerungException;

	/**
	 * Enables the wait status for the "Triebfahrzeug" with the specified
	 * address by sending the command <code>WAIT &lt;address&gt;</code> to the
	 * server.
	 * 
	 * @param address
	 *            The address of the Triebfahrzeug
	 * @return <code>true</code> if the wait was successful
	 * @throws IllegalArgumentException
	 *             thrown if the input parameters are invalid
	 * @throws FahrSteuerungException
	 * @see #parseResponse(String)
	 * @see #getLastResponse()
	 */
	public abstract boolean wait(String address) throws FahrSteuerungException;

	/**
	 * Disable the wait status for the "Triebfahrzeug" with the specified
	 * address.
	 * 
	 * @param address
	 *            The address of the Triebfahrzeug
	 * @return <code>true</code> if the endw was successful
	 * @throws IllegalArgumentException
	 *             thrown if the input parameters are invalid
	 * @throws FahrSteuerungException
	 */
	public abstract boolean endw(String address) throws FahrSteuerungException;

	/**
	 * Set or delete the number of the train for the "Triebfahrzeug" with the
	 * specified address.
	 * 
	 * @param address
	 *            The address of the Triebfahrzeug
	 * @param zn
	 *            The new train number, (if the number is <code>0</code>, the
	 *            number will be deleted)
	 * @return <code>true</code> if the zn was successful
	 * @throws IllegalArgumentException
	 *             thrown if the input parameters are invalid
	 * @throws FahrSteuerungException
	 */
	public abstract boolean zn(String address, String zn) throws FahrSteuerungException;

	/**
	 * Return the number of the train for the "Triebfahrzeug" with the specified
	 * address.
	 * 
	 * @param address
	 *            The address of the Triebfahrzeug
	 * @return The train number, will be <code>null</code> if no number is
	 *         currently set
	 * @throws IllegalArgumentException
	 *             thrown if the input parameters are invalid
	 * @throws FahrSteuerungException
	 */
	public abstract String zn(String address) throws FahrSteuerungException;

	/**
	 * Add the "Triebfahrzeug" with the slave address to the "Triebfahrzeug"
	 * with the master address for multitraction.
	 * 
	 * @param master
	 *            The address of the master Triebfahrzeug
	 * @param slave
	 *            The address of the slave Triebfahrzeug to add to the master
	 * @return <code>true</code> if adding the slave to the master was
	 *         successful
	 * @throws IllegalArgumentException
	 *             thrown if the input parameters are invalid
	 * @throws FahrSteuerungException
	 */
	public abstract boolean addMT(String master, String slave) throws FahrSteuerungException;

	/**
	 * Remove the "Triebfahrzeug" with the slave address from the
	 * "Triebfahrzeug" with the master address for multitraction.
	 * 
	 * @param master
	 *            The address of the master Triebfahrzeug
	 * @param slave
	 *            The address of the slave Triebfahrzeug to remove from the
	 *            master
	 * @return <code>true</code> if removing the slave from the master was
	 *         successful
	 * @throws IllegalArgumentException
	 *             thrown if the input parameters are invalid
	 * @throws FahrSteuerungException
	 */
	public abstract boolean removeMT(String master, String slave) throws FahrSteuerungException;

	/**
	 * Set the "Triebfahrzeug" with the passed address as ready for departure.
	 * 
	 * @param address
	 *            The address of the Triebfahrzeug
	 * @return <code>true</code> if the fertig was successful
	 * @throws IllegalArgumentException
	 *             thrown if the input parameters are invalid
	 * @throws FahrSteuerungException
	 */
	public abstract boolean fertig(String address) throws FahrSteuerungException;

	/**
	 * Set the "Triebfahrzeug" with the passed address to the passed
	 * "Handregler".
	 * 
	 * @param address
	 *            The address of the Triebfahrzeug
	 * @param reglerNr
	 *            The number of the Handregler
	 * @return <code>true</code> if setting to the handregler was successful
	 * @throws IllegalArgumentException
	 *             thrown if the input parameters are invalid
	 * @throws FahrSteuerungException
	 */
	public abstract boolean hndr(String address, int reglerNr) throws FahrSteuerungException;

	/**
	 * Return the last response that has been received from the execution of the
	 * last command. May be used if one of the command functions returns
	 * <code>false</code> to be able to display the cause of the error (which is
	 * normally contained in the response of the command).<br>
	 * Each call to any of the command functions overwrites the previous
	 * response.
	 * 
	 * @return the last response (will be <code>null</code> if no command had
	 *         been executed before)
	 */
	public abstract String getLastResponse();
}